/*********************************************************************************
 *      Copyright:  (C) 2022 Li Yanting<liyanting2@163.com>
 *                  All rights reserved.
 *
 *       Filename:  cmd.c
 *    Description:  This file 
 *                 
 *        Version:  1.0.0(05/06/2022)
 *         Author:  Li Yanting <liyanting2@163.com>
 *      ChangeLog:  1, Release initial version on "05/06/2022 10:08:39"
 *                 
 ********************************************************************************/

#include "at_cmd.h"

int send_cmd(attr_ctx_t *attr, char * at_cmd, char *expect_recv, char *recv_buf, int buf_size, int timeout)
{
    if( !attr || !at_cmd || !expect_recv )
    {
        log_error("function %s invalid parameter\n", __func__);
        return -1;
    }

    char   recv[512] = {0};

    if( serial_send(attr, at_cmd, strlen(at_cmd)) < 0 )
    {
        log_error("function %s send at_cmd failure.\n", __func__);
        return -2;
    }

    if( serial_recv(attr, recv, sizeof(recv), timeout) < 0 )
    {
        log_error("function %s recv message failure.\n", __func__);
        return -3;
    }

    if( !strstr(recv, expect_recv) )
    {
        log_error("function %s can not find expect recv.\n", __func__);
        return -4;
    }

    if( recv_buf )
    {
        if( strncpy(recv_buf, recv, buf_size) < 0 )
        {
            log_error("function %s copy recv to recv_buf failure.\n", __func__);
            return -5;
        }
    }

    return 0;
}

int check_serial_ready(attr_ctx_t *attr)
{
    if( !attr )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }
    
    int rv;

    rv = send_cmd(attr, "AT\r", "OK", NULL, 0, 2);
    if(rv < 0)
    {
        log_error("function %s serial cannot be used.\n", __func__);
        return rv;
    }

    return rv;
}

int check_sim_exist(attr_ctx_t *attr)
{
    if( !attr )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    int    rv;

    rv = send_cmd(attr, "AT+CPIN?\r", "READY", NULL, 0, 2); 
    if(rv < 0)
    {
        log_error("function %s can not found SIM\n", __func__);
        return rv;
    }

    return rv;
}

int check_sim_register(attr_ctx_t *attr)
{
    if( !attr )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    int    rv;

    rv = send_cmd(attr, "AT+CREG?\r", "0,1", NULL, 0, 2); 
    if(rv < 0)
    {
        log_error("function: %s SIM card is not registered\n", __func__);
        return rv;
    }

    return rv;
}

int check_signal_strength(attr_ctx_t *attr)
{
    if( !attr )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    int      rv;
    char     recv[128] = {0};
    int      i;
    char     str_signal_strength[16] = {0};
    int      signal_strength;

    rv = send_cmd(attr, "AT+CSQ\r", "+CSQ", recv, sizeof(recv), 2);
    if(rv < 0)
    {
        log_error("check signal strength failure.\n");
        return -1;
    }

    for( i=0; i<sizeof(recv); i++)
    {
        if( recv[i] == ',' )
        {
            if( recv[i-2] == ' ' )
            {
                strncpy(str_signal_strength, &recv[i-1], 1);
            }
            else
            {
                strncpy(str_signal_strength, &recv[i-2], 2);
            }

            break;
        }
    }   

    signal_strength = atoi(str_signal_strength);

    if( signal_strength < 7 || signal_strength == 99 )
    {
        printf("signal strength: %d -weak or not.\n", signal_strength);
        return -2;
    }

    return 0;

}

// int check_sim_allready(attr_ctx_t *attr)
// {
//     if( !attr )
//     {
//         log_error("function %s invalid parameter.\n", __func__);
//         return -1;
//     }

//     if(check_sim_exist(attr) < 0)
//     {
//         log_error("function: %s SIM card can not be detected!\n", __func__);
//         return -2;
//     }

//     if(check_sim_register(attr) < 0)
//     {
//         log_error("function: %s SIM card is not registered!\n", __func__);
//         return -3;
//     }

//     if(check_signal_strength(attr) < 0)
//     {
//         log_error("function: %s signal strength not requirements!\n", __func__);
//         return -4;
//     }

//     return 0;
// }

int check_sim_allready(attr_ctx_t *attr, gsm_ctx_t *st_gsm)
{
    int    rv = 0;

    if(!attr || !st_gsm)
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    switch(st_gsm->status)
    {
        case GSM_STATUS_INIT:
            if((rv = check_serial_ready(attr)) < 0)
            {
                log_error("function: %s serial not ready!\n", __func__);
                break;
            }
            st_gsm->status ++;

        case GSM_STATUS_SERIAL_READY:
            if((rv = check_sim_exist(attr)) < 0)
            {
                log_error("function: %s SIM card can not be detected!\n", __func__);
                break;
            }
            st_gsm->status ++;
        
        case GSM_STATUS_SIM_EXIST:
            if((rv = check_sim_register(attr)) < 0)
            {
                log_error("function: %s SIM card is not registered!\n", __func__);
                break;
            }
            st_gsm->status ++;

        case GSM_STATUS_SIM_REG:
            if((rv = check_signal_strength(attr)) < 0)
            {
                log_error("function: %s signal strength not requirements!\n", __func__);
                break;
            }
            st_gsm->status ++;
        default: 
            break;
    }

    return st_gsm->status;
}

int get_center_number(attr_ctx_t *attr, char *center_number_buf)
{
    if( !attr || !center_number_buf )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    char   *p_recv = NULL;
    char    recv[128] = {0};
    int     center_number_len = 14;

    if( send_cmd(attr, "AT+CSCA?\r", "OK", recv, sizeof(recv), 2) < 0 )
    {
        log_error("function %s get sms center number failure.\n", __func__);
        return -2;
    }

    p_recv = strstr(recv, "CSCA");
    p_recv += 7;

    strncpy(center_number_buf, p_recv, center_number_len);

    return 0;

}

int send_text_sms( attr_ctx_t *attr, char *phone_number, char *sms )
{
    if( !attr || !phone_number || !sms )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    int    rv;
    char   cmd[32]={0};

    rv = send_cmd(attr, "AT+CMGF=1\r", "OK", NULL, 0, 2);
    if(rv < 0)
    {
        log_error("function %s set SMS mode to text mode failure.\n", __func__);
        return -2;
    }

    snprintf(cmd, sizeof(cmd), "AT+CMGS=\"%s\"\r", phone_number);
    rv = send_cmd(attr, cmd, ">", NULL, 0, 2);
    if(rv < 0)
    {
        log_error("function %s can not receive \">\".\n", __func__);
        return -4;
    }

    strcat(sms,"\x1a");
    rv = send_cmd(attr, sms, "OK", NULL, 0, 2);
    if(rv < 0)
    {
        log_error("function %s send sms failure.\n", __func__);
        return -5;
    }

    return 0;
}

int send_pdu_sms(attr_ctx_t *attr, char *phone_number, char *sms)
{

    if( !attr || !sms || !phone_number )
    {
        log_error("function %s invalid parameter.\n", __func__);
        return -1;
    }

    char  cmd[32]={0};
    char  pdu_sms[1090] = {0};
    int   msg_len = 0;
    char  sms_center_number[128] = {0};

    if( get_center_number(attr, sms_center_number) < 0 )
    {
        log_error("function %s get sms center number failure.\n", __func__);
        return -2;
    }

    if( pdu_encode(sms, sms_center_number, phone_number, pdu_sms, sizeof(pdu_sms), &msg_len) < 0 )
    {
        log_error("function %s pdu convert failure.\n", __func__);
        return -3;
    }

    if( send_cmd(attr, "AT+CMGF=0\r", "OK", NULL, 0, 2) < 0 )
    {
        log_error("function %s set SMS mode to text mode failure.\n", __func__);
        return -4;
    }

    snprintf(cmd, sizeof(cmd), "AT+CMGS=%d\r", msg_len);

    if(send_cmd(attr, cmd, ">", NULL, 0, 2) < 0)
    {
        log_error("function %s can not receive \">\".\n", __func__);
        return -6;
    }

    strcat(pdu_sms,"\x1a");

    if( send_cmd(attr, pdu_sms, "OK", NULL, 0, 2) < 0 )
    {
        log_error("function %s send pdu sms failure.\n", __func__);
        return -5;
    }

    return 0;

}

int delete_all_sms(attr_ctx_t *attr)
{
    if( !attr )
    {
        log_error("function %s invalid parameter\n", __func__);
        return -1;
    }

    if( send_cmd(attr, "AT+CMGD=1,4\r", "OK", NULL, 0, 2) < 0 )
    {
        log_error("delete all sms failure.\n");
        return -2;
    }

    return 0;
}

int get_recv_sms(char *recv, char *str_sms_buf)
{
    char                *p_str_sms = NULL;
    char                *p_str = NULL;
    char                *p_str_end = NULL;

    // p_str_sms = recv;

    if((p_str = strstr(recv, "+CMGR:")) == NULL)
    {
        return -1;
    }

    p_str_sms = strstr(p_str,"\r\n");
    p_str_sms += 2;
    p_str_end = strstr(p_str_sms,"\r\n");

    strncpy(str_sms_buf, p_str_sms, (int)(p_str_end - p_str_sms));

    // p_str_sms_end = strstr(recv, "OK");
    // *(p_str_sms_end-3)=0;

    // if( strlen(recv) < 216 )
    // {
    //     p_str_sms += 16;
    // }
    // else
    // {
    //     p_str_sms += 17;
    // }
    // memcpy(str_sms_buf, p_str_sms, strlen(p_str_sms));

    return 0;
}

int get_specify_sms(attr_ctx_t *attr, int index)
{
    if( !attr )
    {
        log_error("function %s invalid parameter\n", __func__);
        return -1;
    }

    char      cmd[16] = {0};
    char      str_sms_buf[512] = {0};
    char      recv[512] = {0};

    sprintf(cmd, "AT+CMGR=%d\r", index);

    if( send_cmd(attr, "AT+CMGF=0\r", "OK", NULL, 0, 2) < 0 )
    {
        log_error("set sms model failure.\n");
        return -2;
    }
        
    if( send_cmd(attr, cmd, "CMGR", recv, sizeof(recv), 2) < 0 )
    {
        log_error("can not find CMGR.\n");
        return -3;
    }

    if( get_recv_sms(recv, str_sms_buf) < 0 )
    {

        log_error("get str sms failure.\n");
        return -4;
    }

    if( display_sms(str_sms_buf) < 0 )
    {
        log_error("read sms failure.\n");
        return -5;
    }

    return 0;
}

int display_all_sms(attr_ctx_t *attr)
{
    int    index = 0;
    
    while(1)
    {
        printf("index: %d\n", index);
        if( -3 == get_specify_sms(attr, index) )
        {
            return 1;
        }
        index++;
        usleep(100000);
    }
    return 0;
}

int listen_sms(attr_ctx_t *attr, char *num, int timeout, char *num_buf, char *ctr_num_buf, char *time_buf, char *utf8_buf)
{
    if( !attr || timeout < 0 || !num_buf || !ctr_num_buf || !time_buf || !utf8_buf )
    {
        log_error("function: %s invalid parameter.\n", __func__);
        return -1;
    }

    int                  rv = -1;
    fd_set               rset;
    struct timeval       st_timeout;

    char                 rbuf[1024] = {0};
    char                 recv_str[512] = {0};
    char                 str_sms[512] = {0};
    char                 sms_num[32] = {0};
    char                 ctr_num[32] = {0};
    char                 time[32] = {0};
    char                 utf8[512] = {0};

    char                *p_idx = NULL;
    char                *p_idx_end = NULL;
    char                 idx[32] = {0};
    char                 cmd[64] = {0};

    st_timeout.tv_sec = (time_t)(timeout)/1000;
    st_timeout.tv_usec = 0;
    
    FD_ZERO(&rset);
    FD_SET(attr->fd, &rset);
    
    if(0 == timeout )
    {
        rv = select(attr->fd+1, &rset, NULL, NULL, NULL);
    }
    else
    {
        rv = select(attr->fd+1, &rset, NULL, NULL, &st_timeout);
    }

    if(rv < 0)
    {
        // printf("function %s select failed: %s\n", __func__, strerror(errno));
        return -2;
    }
    else if(0 == rv)
    {
        // printf("select time out\n");
        return -3;
    }
    else
    {
        memset(rbuf, 0, sizeof(rbuf));
        memset(idx, 0, sizeof(idx));
        memset(cmd, 0, sizeof(cmd));
        memset(recv_str, 0, sizeof(recv_str));
        memset(str_sms, 0, sizeof(str_sms));
        memset(sms_num, 0, sizeof(sms_num));
        memset(ctr_num, 0, sizeof(ctr_num));
        memset(time, 0, sizeof(time));
        memset(utf8, 0, sizeof(utf8));


        rv = read(attr->fd, rbuf, sizeof(rbuf));
        if( rv <= 0 )
        {
            log_error("function %s read from serial[%d] failure: %s.\n", __func__, attr->fd, strerror(errno));
            return -4;
        }

        if( strstr(rbuf, "+CMTI") )
        {
            if( send_cmd(attr, "AT+CMGF=0\r", "OK", NULL, 0, 2) < 0 )
            {
                log_error("set sms model failure.\n");
                return -5;
            }

            p_idx = (strstr(rbuf, ",") + 1 );
            p_idx_end = (strstr(rbuf, "\r\n"));
            memcpy(idx, p_idx, (int)(p_idx_end-p_idx));
            log_debug("index:%s\n", idx);

            snprintf(cmd, sizeof(cmd)+1, "AT+CMGR=%s\r", idx);
            
            if( send_cmd(attr, cmd, "+CMGR", recv_str, sizeof(recv_str), 2) < 0 )
            {
                log_error("get sms string failure.\n");
                return -6;
            }

            if( get_recv_sms(recv_str, str_sms) < 0 )
            {
                log_error("get_recv_sms failure.\n");
                return -7;
            }

            if( pdu_decode(str_sms, sms_num, ctr_num, time, utf8) < 0 )
            {
                log_error("recv to utf8 failure.\n");
                return -7;
            }
                
            if( num )
            {
                if( strcmp(num, sms_num) != 0 )
                {
                    strcpy(num_buf, sms_num);
                    strcpy(ctr_num_buf, ctr_num);
                    strcpy(time_buf, time);
                    strcpy(utf8_buf, utf8);

                    return -8;
                }

            }

            strcpy(num_buf, sms_num);
            strcpy(ctr_num_buf, ctr_num);
            strcpy(time_buf, time);
            strcpy(utf8_buf, utf8);
        }
        else
        {
            return -10;
        }
    }

    return 0;
}

int display_spci_num_sms(attr_ctx_t *attr, char *specify_numb)
{
    char         time[32] = {0};
    char         sms_numb[32] = {0};
    char         cent_numb[32] = {0};
    char         utf8_sms[512] = {0};
    char         recv_str[512] = {0};
    char         sms_str[512] = {0};
    
    char         cmd[16] = {0};
    int          index = 0;
    int          rv = 0;

    if( send_cmd(attr, "AT+CMGF=0\r", "OK", NULL, 0, 2) < 0 )
    {
        log_error("set sms model failure.\n");
        return -2;
    }

    while(1)
    {
        memset(time, 0, sizeof(time));
        memset(sms_numb, 0, sizeof(sms_numb));
        memset(cent_numb, 0, sizeof(cent_numb));
        memset(utf8_sms, 0, sizeof(utf8_sms));
        memset(recv_str, 0, sizeof(recv_str));
        memset(sms_str, 0, sizeof(sms_str));

        sprintf(cmd, "AT+CMGR=%d\r", index);
        rv = send_cmd(attr, cmd, "CMGR", recv_str, sizeof(recv_str), 2);

        if( -4 == rv )
        {
            break;
        }
        else if (0 == rv)
        {
            printf("index: %d\n", index);
        }
        else
        {
            log_error("get str sms failure.\n");
            return -1;
        }
        
        if( get_recv_sms(recv_str, sms_str) < 0 )
        {
            log_error("get str sms failure.\n");
            return -2;
        }

        if( pdu_decode(sms_str, sms_numb, cent_numb, time, utf8_sms) < 0 )
        {
            log_error("get utf8 sms failure.\n");
            return -3;
        }

        if( 0 == strcmp(specify_numb, sms_numb) )
        {
            printf("time: %s\n", time);
            printf("sms center number: %s\n", cent_numb);
            printf("phone number: %s\n", sms_numb);
            printf("sms: %s\n", utf8_sms);
            printf("\n");
        }

        index++;
        usleep(5000);
    }

    return 0;
}

int display_sms(char *str_buf)
{
    int          i = 0;
    char         temp;

    char         *p_f = str_buf+24;
    char          f[64] = {0};

    int           phone_len = 0;
    char          str_phone_len[4] = {0};
    char         *p_phone_len = str_buf+20;
    char          phone_type[4] = {0};
    char         *p_phone_type = str_buf+22;
    int           head_len = 0;

    char         *p_str_buf = str_buf;
    char         head[128] = {0};
    char         *p_head = head;
    char         sms_center_number_buf[16] = {0};
    char         time_buf[16] = {0};
    char         sms_center_number[32] = {0};
    char         phone_number_buf[30] = {0};
    char         phone_number[32] = {0};
    char         time[32] = {0};
    char         sms_type[4] = {0};
    char         *p_time = time_buf;
    
    int          bit7_to_unic_len = 0;

    /* iconv() */
    iconv_t      cd;
    char         unic_buf[MAX_UNIC_LEN] = {0};
    char         *p_unic_start = unic_buf;
    int          unic_len = MAX_UNIC_LEN;
    char         utf8[512] = {0};
    char         *p_utf8_buf = utf8;
    int          utf8_size = sizeof(utf8);

    memcpy(str_phone_len, p_phone_len, 2);
    phone_len = htoi(str_phone_len);

    memcpy(f, p_f, (phone_len+20));
    if( strstr(f, "F") )
    {
        head_len = 45+phone_len;
    }
    else
    {
        head_len = 44+phone_len;
    }

    memcpy(phone_type, p_phone_type, 2);

    for(i=0; i<head_len/2; i++)
    {
        temp = *p_str_buf;
        *p_str_buf = *(p_str_buf+1);
        *(p_str_buf+1) = temp;
        p_str_buf+=2;
    }
    memcpy(head, str_buf, head_len);

    memcpy(time_buf, (p_head+(head_len-16)), 12);
    sprintf(time, "%c%c-%c%c-%c%c %c%c:%c%c:%c%c", \
        *p_time, *(p_time+1), *(p_time+2), *(p_time+3), *(p_time+4), *(p_time+5), \
            *(p_time+6), *(p_time+7), *(p_time+8), *(p_time+9), *(p_time+10), *(p_time+11));

    memcpy(sms_center_number_buf, (p_head+4), 13);
    sprintf(sms_center_number, "+%s", sms_center_number_buf);

    memcpy(phone_number_buf, (p_head+24), phone_len);
    sprintf(phone_number, "+%s", phone_number_buf);

    memcpy(sms_type, (p_head+head_len-18), 2);
    if( strcmp(sms_type, "00") == 0)
    {
        bit7_to_unic(p_str_buf, unic_buf, &bit7_to_unic_len);
        for( i=0; i<bit7_to_unic_len; i+=2)
        {
            temp = unic_buf[i];
            unic_buf[i] = unic_buf[i+1];
            unic_buf[i+1] = temp;
        }
    }
    else
    {
        str_to_hex(p_str_buf, unic_buf);
        for( i=0; i<(strlen(str_buf)-head_len)/2; i+=2)
        {
            temp = unic_buf[i];
            unic_buf[i] = unic_buf[i+1];
            unic_buf[i+1] = temp;
        }
    }

    cd = iconv_open("UTF-8", "UNICODE");
    if(cd < 0)
    {
        log_error("function %s iconv_open failed.\n", __func__);
        return -1;
    }
    if( iconv(cd, &p_unic_start, (size_t *)&unic_len, &p_utf8_buf, (size_t *)&utf8_size) < 0)
    {
        log_error("iconv failed\n");
        return -2;
    }
    iconv_close(cd);

    printf("time: %s\n", time);
    printf("sms_center_number: %s\n", sms_center_number);
    printf("phone_number: %s\n", phone_number);
    printf("sms: %s\n", utf8);
    printf("\n");  

    return 0;
}

// int dial_up(attr_ctx_t *attr)
// {
//     // FILE      *fp;
//     // char       termios_cmd[32] = {0};

//     if( send_cmd(attr, "AT+QCFG=\"usbnet\",1\r", "OK", NULL, 0, 2) < 0 )
//     {
//         log_error("set ECM failure.\n");
//         return -2;
//     }
//     if( send_cmd(attr, "AT+QCFG=\"usbnet\"\r", "1", NULL, 0, 2) < 0 )
//     {
//         log_error("set ECM failure.\n");
//         return -3;
//     }
//     if( send_cmd(attr, "AT+qnetdevctl=1,1,1\r", "OK", NULL, 0, 2) < 0 )
//     {
//         log_error("set ECM failure.\n");
//         return -4;
//     }
    
//     // sprintf(termios_cmd, "sudo route add default gw usb0");
//     // if( NULL == (fp=popen(termios_cmd, "r")) )
//     // {
//     //     printf("popen() to excute command \"%s\" failure: %s\n", termios_cmd, strerror(errno));
//     //     return -5;
//     // }

//     return 0;
// }